/* 
 * File:   ParsedDataString.h
 * Author: Jeffrey Geyssens
 *
 *
 * Created on August 8, 2010, 5:52 AM
 */

#ifndef _PARSEDDATASTRING_H
#define	_PARSEDDATASTRING_H
#include <string>
#include <vector>
#include <map>
#include "DMLStatement.h"
#include "Derivation.h"
#include "Section.h"

using namespace std;
//OutputCode:
//For SQLGenerator use
//Actions permitted on each data string will depend on the output code

enum OutputCode {
    OK, NOSQL, BADSYNTAX
};

class ParsedDataString {
public:
    ParsedDataString();
    ParsedDataString(const ParsedDataString& orig);
    virtual ~ParsedDataString();

    string getDS();
    void setDS(const string& statement);
    string getContent(int unprocessed_resultNo);
    vector<string>& getContent();

    void addContent(string s);
    void loadContent(string s);
    void modifyContent(string s, int unprocessed_resultNo);
    void removeContent(int unprocessed_resultNo);

    bool setStructure();
    Derivation& getStructure();
    void getStructureSQL();

    //Set the all SQL statements related to the data string
    bool setSQLvect(vector<DMLStatement> DMLvect);

    OutputCode getOutputCode();

    friend ostream & operator<<(ostream&, const ParsedDataString&);
    void print();
    void printStruct();
    void printDisplay();
    void printPK();
    void printVal();





private:
    //An unprocessed_result has several numbered columns
    //Each column contains a string, one of which holds the actual data string.

    //The semantics for each column are defined in the header.
    //We use the section container because of the convienient buildfile methods.
    int pm;
    //Holds orgin data string
    string DS;
    //Holds actual generated string x = y
    Section<string> unprocessed_result;
    //Did parsing result in an error?
    bool error;
    //If successful store the found structure here to compare with
    //storage container:
    Derivation structure;
    //Vector of useless DML statements which contain the original
    //parameterized DML statements for a data string
    vector<DMLStatement> displaystatements;
    //Vector of DML statements of which the attribute values are replaced
    //with the actual values and primary keys of reference terminals:
    vector<DMLStatement> PKstatements;
    //Vector of DML statements of which the attribute values are replaced
    //with the actual values and parse results of reference terminals:
    vector<DMLStatement> dummystatements;

    OutputCode outputcode;


};
//Constructor

ParsedDataString::ParsedDataString() {
    pm = 1;
}
//Copy Constructor

ParsedDataString::ParsedDataString(const ParsedDataString& orig) {
    unprocessed_result = orig.unprocessed_result;
    pm = orig.pm;
    error = orig.error;
    structure = orig.structure;
    DS = orig.DS;
    outputcode = orig.outputcode;
}
//Destructor

ParsedDataString::~ParsedDataString() {
}

string ParsedDataString::getContent(int unprocessed_resultNo) {
    return unprocessed_result.get(unprocessed_resultNo);
}

vector<string>& ParsedDataString::getContent() {
    return unprocessed_result.getSectionData();
}

void ParsedDataString::addContent(string s) {
    string& data = s;
    char datatype = data[1];

    //cout << "HERE I AM" << endl;
    switch (datatype) {


        case 'L':
        {
            stringstream nochar;

            //First remove all whitespaces, tabs and newlines from the statement
            string::const_iterator iterator1 = data.begin();


            if (data.find("&INT") != data.npos) {
                stringstream ssfront;
                ssfront << "(L:&INT[" << pm << "]) ";
                ssfront << data.substr(data.find("="), data.size());
                data = ssfront.str();


            } else {

                while (iterator1 != data.end()) {
                    if (*iterator1 != '\'')
                        nochar << *iterator1;
                    iterator1++;
                }
                data = nochar.str();
                data.insert(data.begin() + 3, '\"');

                data.erase(data.size() - 1, 1);

                stringstream datatail;
                datatail << data << "\"[" << pm << "])";
                data = datatail.str();

            }
            cout << data << endl;
        }
            break;

        case 'D':
        {
            int i = data.find('=');
            if (i > 0) {
                stringstream ssdata;
                ssdata << data.substr(0, i - 2) << "[" << pm << "])";

                ssdata << " " << data.substr(i, data.size() - i);
                data = ssdata.str();
                cout << data << endl;
            }
        }
            break;

        case 'R':
        {
            int i = data.find('=');
            if (i > 0) {
                stringstream ssdata;
                ssdata << data.substr(0, i - 2) << "[" << pm << "])";
                ssdata << " = \"";
                int j = data.find("<");
                int m = data.find(">");
                if (j > 0)
                    ssdata << data.substr(i + 3, data.size() - i - 4);
                else
                    ssdata << data.substr(i + 2, data.size());
  
                ssdata << "\"";
                data = ssdata.str();

                cout << data << endl;
            }
        }
            break;

        default:
        {
            // cout << "Storage elements:" << endl;
        }
            break;
    }
    pm = pm + 1;
    unprocessed_result.add(data);

}

void ParsedDataString::loadContent(string s) {
    unprocessed_result.add(s);

}

ostream & operator<<(ostream& output, const ParsedDataString & data) {
    //Ask Dates
    ParsedDataString PDS;
    PDS = data;
    vector<string> x;
    x = PDS.unprocessed_result.getSectionData();
    vector<string>::iterator It1;
    stringstream format;

    for (It1 = x.begin(); It1 != x.end(); ++It1) {
        string& value = (*It1);
        format << value << "\n";
    }

    return output << format.str();

}

bool ParsedDataString::setStructure() {
    vector<string> stringvector;
    //Prepare to navigate
    stringvector = unprocessed_result.getSectionData();


    vector<string>::iterator stringp;

    for (stringp = stringvector.begin(); stringp != stringvector.end();
            ++stringp) {
        string& currentresult = (*stringp);

        char datatype = currentresult[1];
        string name, value;
        if (datatype == 'L') {

            if (name.find("&INT") != currentresult.npos) {
                //cout << "in d" << endl;
                int equalpos;
                LiteralTerminal lterminal;
                equalpos = currentresult.find("=");
                if (currentresult.npos == equalpos) {
                    return false;
                }
                name = currentresult.substr(0, equalpos - 1);
                value = currentresult.substr(equalpos + 2, currentresult.size());

                //Get value between " " located in the name of LT.

                lterminal.setId(name);
                lterminal.setValue(value);
                structure.addElement(lterminal);
                outputcode = OK;



            } else {

                //The name is exactly whats on current result

                int quotepos;
                LiteralTerminal terminal;
                name = currentresult;
                //Get value between " " located in the name of LT.
                quotepos = currentresult.find("\"");
                if (currentresult.npos == quotepos) {
                    return false;
                }
                value = name.substr(4, name.size());
                value = value.substr(0, value.find("\""));

                terminal.setId(name);
                terminal.setValue(value);
                structure.addElement(terminal);
                outputcode = OK;
            }
        }

        if (datatype == 'D') {
            //cout << "in d" << endl;
            int equalpos;
            DataReferenceTerminal terminal;
            equalpos = currentresult.find("=");
            if (currentresult.npos == equalpos) {
                return false;
            }
            name = currentresult.substr(0, equalpos - 1);
            value = currentresult.substr(equalpos + 2, currentresult.size());

            //Get value between " " located in the name of LT.

            terminal.setId(name);
            terminal.setValue(value);
            structure.addElement(terminal);
            outputcode = OK;
        }

        if (datatype == 'R') {
            int equalpos;
            ReferenceTerminal terminal;
            equalpos = currentresult.find("=");
            if (currentresult.npos == equalpos) {
                return false;
            }
            name = currentresult.substr(0, equalpos - 1);
            value = currentresult.substr(equalpos + 2, currentresult.size());

            //Get value between " " located in the name of LT.

            terminal.setId(name);
            terminal.setValue(value);
            structure.addElement(terminal);
            outputcode = OK;


        }
        if (datatype == 'S') {
            int equalpos;
            StoredTerminal terminal;
            equalpos = currentresult.find("=");
            if (currentresult.npos == equalpos) {
                return false;
            }
            name = currentresult.substr(0, equalpos - 1);
            string rest, drt;
            rest = currentresult.substr(equalpos + 2, currentresult.size());

            equalpos = rest.find("=");
            if (rest.npos == equalpos) {
                return false;
            }
            drt = rest.substr(0, equalpos - 1);
            value = rest.substr(equalpos + 2, rest.size());
            //Get value between " " located in the name of LT.

            terminal.setId(name);
            terminal.setValue(value);
            terminal.setMasked(drt);
            structure.addElement(terminal);
            outputcode = OK;


        }

        if (datatype == 'E') {
            //cout << BADSYNTAX << endl;
            error = true; //Syntax Error
            outputcode = BADSYNTAX;
        }

    }

    return true;
}

Derivation& ParsedDataString::getStructure() {
    return structure;
}

bool ParsedDataString::setSQLvect(vector<DMLStatement> DMLvect) {
    //In

    //Init all vectors
    displaystatements = DMLvect;
    PKstatements = DMLvect;
    dummystatements = DMLvect;

    //Check if SQL statements where found for PDS
    if ((DMLvect.size() == 0) && (outputcode == OK)) {
        outputcode = NOSQL;
    }
    vector<DMLStatement>::iterator DMLiter;
    vector<DMLStatement>::iterator PKiter;
    //We use assignRT to modify the DML statement attribute values
    //We must iterate through the structure of the data string the old
    //fashion way, by check it's size and then iterate by entry number
    //en incrementing it.
    int derivsize = structure.size();
    //cout << derivsize << endl;
    //cout << structure.getValue(1);

    //We iterate over the dummystatements vector and apply changes.
    PKiter = PKstatements.begin();
    for (DMLiter = dummystatements.begin(); DMLiter != dummystatements.end();
            ++DMLiter) {
        for (int i = 1; i != derivsize + 1; i++) {
            string RT, val;
            RT = structure.getElement(i);
            val = structure.getValue(i);
            cout << RT << "::" << val << endl;
            (*DMLiter).assignRT(RT, val);

        }
        ++PKiter;
    }
    return true;
}

OutputCode ParsedDataString::getOutputCode() {
    return outputcode;
}

void ParsedDataString::setDS(const string& datastring) {
    DS = datastring;
}

string ParsedDataString::getDS() {
    return DS;
}

void ParsedDataString::printDisplay() {
    vector<DMLStatement>::iterator DMLiter;
    for (DMLiter = displaystatements.begin(); DMLiter != displaystatements.end();
            ++DMLiter) {
        (*DMLiter).rebuildStatement(0);
        (*DMLiter).print();
    }
}

void ParsedDataString::printPK() {
    vector<DMLStatement>::iterator DMLiter;
    for (DMLiter = PKstatements.begin(); DMLiter != PKstatements.end();
            ++DMLiter) {
        (*DMLiter).print();
    }
}

void ParsedDataString::printVal() {
    vector<DMLStatement>::iterator DMLiter;
    for (DMLiter = dummystatements.begin(); DMLiter != dummystatements.end();
            ++DMLiter) {
        (*DMLiter).rebuildStatement(1);
        (*DMLiter).print();
    }
}

void ParsedDataString::print() {
    unprocessed_result.print();
}

#endif	/* _PARSEDDATASTRING_H */